package com.jgp.sys.utils;

import com.jgp.common.persistence.Model;
import com.jgp.common.pojo.LabelValue;
import com.jgp.common.utils.JGPUtil;
import com.jgp.sys.query.QueryFilterList;
import com.jgp.sys.repository.JGPRepository;
import com.jgp.sys.ui.FormResult;
import com.jgp.sys.ui.GridResult;
import com.jgp.sys.ui.Pager;
import com.jgp.sys.ui.model.Field;
import org.springframework.util.Assert;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 项目   sys
 * 作者   loufei
 * 时间   2018/3/10
 */
public class ResultUtil {
    
    public static FormResult transform(String prefix, Object object) {
        return transform(prefix, JGPUtil.toMap(object));
    }
    
    public static FormResult transform(Object... object) {
        FormResult result = null;
        if (object.length == 1) {
            result = transform(null, JGPUtil.toMap(object[0]));
        } else {
            for (Object obj : object) {
                FormResult transformResult = transform(JGPUtil.getModelPrefix(obj.getClass()), JGPUtil.toMap(obj));
                if (null == result) {
                    result = transformResult;
                } else {
                    result.addFields(transformResult.getFields());
                }
            }
        }
        return result;
    }
    
    private static FormResult transform(String prefix, Map<String, Object> beanMap) {
        List<Field> fields = new ArrayList<>();
        beanMap.forEach((name, value) -> {
            Field field = new Field();
            field.setPrefix(prefix);
            field.setValue(value);
            field.setName(name);
            fields.add(field);
        });
        
        FormResult formResult = new FormResult();
        formResult.addFields(fields);
        return formResult;
    }
    
    public static GridResult transform(Pager pager, List<GridResult.Category> cats, List<Object> selectedKeys, List<?>... objects) {
        
        GridResult gridResult = new GridResult();
        gridResult.setPager(pager);
        
        Map<String, GridResult.Category> needMapperCat = new HashMap<>();
        
        for (GridResult.Category cat : cats) {
            if (Objects.nonNull(cat.getMapperClass()) || Objects.nonNull(cat.getActiveKey()) || Objects.nonNull(cat.getDataSourceList())) {
                needMapperCat.put(cat.getName() + "|-|" + JGPUtil.random(6), cat);
            }
        }
        
        gridResult.setSelectedKeys(selectedKeys);
        
        Map<String, List<Object>> mapperValues = new HashMap<>();
        
        gridResult.setRecords(Arrays.asList(objects).parallelStream().filter(Objects::nonNull).flatMap(List::stream).map(o -> {
            Class clazz = o.getClass();
            Map<String, Object> beanMap;
            if (Model.class.isAssignableFrom(clazz)) {
                beanMap = (Map) operatorModelExtData(o);
            } else {
                beanMap = JGPUtil.toMap(o);
            }
            
            String prefix = JGPUtil.getModelPrefix(clazz);
            
            for (String fieldName : needMapperCat.keySet()) {
                if (Objects.isNull(mapperValues.get(fieldName))) {
                    mapperValues.put(fieldName, new ArrayList<>());
                }
                String name = fieldName.split("\\|-\\|")[0];
                Object value = beanMap.get(name);
                if (name.contains(".")) {
                    String[] arr = name.split("\\.");
                    Object nested = beanMap.get(arr[0]);
                    if (Objects.nonNull(nested)) {
                        value = ((Map) nested).get(arr[1]);
                    }
                }
                if (Objects.nonNull(value)) {
                    mapperValues.get(fieldName).add(value);
                } else {
                    mapperValues.get(fieldName).add("");
                }
            }
            
            return transform(prefix, beanMap);
        }).collect(ArrayList::new, (m, v) -> {
            m.add(v);
        }, ArrayList::addAll));
        
        Map<Class,Set<Object>> mapVs = new HashMap<>();
    
        mapperValues.forEach(((catName, values)->{
            GridResult.Category cat = needMapperCat.get(catName);
            Set<Object> vs = mapperValues.get(catName).stream().filter(Objects::nonNull).collect(Collectors.toSet());
            Set vsWrap = mapVs.get(cat.getMapperClass());
            if(Objects.nonNull(vsWrap)){
                vsWrap.addAll(vs);
            }else{
                mapVs.put(cat.getMapperClass(),vs);
            }
        }));
        
        Map<Class,List<Object>> persistReadValues = new HashMap<>();
        
        mapperValues.forEach((catName, values) -> {
            GridResult.Category cat = needMapperCat.get(catName);
            Class mapperClass = cat.getMapperClass();
            JGPRepository jgpRepository = null;
            List list = null;
            
            String relationName = "id";
            if (Objects.nonNull(cat.getRelationName())) {
                relationName = cat.getRelationName();
            }
            cat.setRelationName(relationName);
            if (Objects.nonNull(mapperClass)) {
                Set<Object> inVs = mapVs.get(mapperClass);
    
                if (Objects.isNull(inVs) || inVs.size() == 0) {
                    return;
                }
                list = persistReadValues.get(mapperClass);
                if(Objects.isNull(list)){
                    QueryFilterList filters = new QueryFilterList();
                    filters.addFilter(relationName, "in", inVs);
    
                    if (JGPRepository.class.isAssignableFrom(mapperClass)) {
                        jgpRepository = (JGPRepository) SpringContextUtil.getBean(mapperClass);
                        list = jgpRepository.read(filters, cat.getMapperName(), relationName);
        
                    } else if (Model.class.isAssignableFrom(mapperClass)) {
                        String modelName = mapperClass.getName();
                        String repositoryName = modelName.replace(".model.", ".repository.").replace(".secmodel.", ".secrepository.") + "Repository";
                        try {
                            jgpRepository = (JGPRepository) SpringContextUtil.getBean(Class.forName(repositoryName));
                        } catch (ClassNotFoundException e) {
                            e.printStackTrace();
                        }
                        list = jgpRepository.read(filters, cat.getMapperName(), relationName);
                    }
                    persistReadValues.put(mapperClass,list);
                }
            } else if (Objects.nonNull(cat.getDataSourceList())) {
                Set<Object> vs = values.stream().filter(Objects::nonNull).collect(Collectors.toSet());
                list = cat.getDataSourceList().get(relationName, cat.getMapperName(), vs);
                if (list.size() > 0) {
                    Map<String, Object> map = JGPUtil.toMap(list.get(0));
                    Set<String> keySet = map.keySet();
                    Assert.isTrue(
                            keySet.contains(relationName) && keySet.contains(cat.getMapperName()),
                            "数据集必须包含关系字段:" + cat.getRelationName() + "和被映射字段:" + cat.getMapperName()
                    );
                }
            }
            if (Objects.nonNull(cat.getActiveKey())) {
                if (Objects.nonNull(list)) {
                    Map<String, LabelValue> valueMap = DropUtil.get(cat.getActiveKey());
                    List midList = new ArrayList();
                    for (Object o : list) {
                        Map<String, Object> map = JGPUtil.toMap(o);
                        Object value = map.get(cat.getMapperName());
                        Object realValue = valueMap.get(value);
                        if (Objects.nonNull(realValue)) {
                            map.put(cat.getMapperName(), JGPUtil.toMap(realValue).get("label"));
                            midList.add(map);
                        }
                    }
                    list = midList;
                } else {
                    cat.setMapperName("label");
                    cat.setRelationName("value");
                    list = DropUtil.getList(cat.getActiveKey());
                }
            }
            if (Objects.nonNull(list)) {
                cat.setDisplayValues(list);
            }
        });
        gridResult.setCats(cats);
        return gridResult;
    }
    
    
    public static Object operatorModelExtData(Object object) {
        if (Objects.isNull(object)) return object;
        Class clazz = object.getClass();
        if (Model.class.isAssignableFrom(clazz)) {
            object = newObject(object);
        } else if (Collection.class.isAssignableFrom(clazz)) {
            Collection list = (Collection) object;
            if (list.size() > 0) {
                object = list.stream().map(ResultUtil::operatorModelExtData).collect(Collectors.toList());
            }
        } else if (Map.class.isAssignableFrom(clazz)) {
            Map map = (Map) object;
            if (map.size() > 0) {
                map.forEach((key, obj) -> {
                    map.put(key, operatorModelExtData(obj));
                });
                object = map;
            }
        }
        return object;
    }
    
    private static Object newObject(Object object) {
        Class clazz = object.getClass();
        if (Model.class.isAssignableFrom(clazz)) {
            String json = JGPUtil.toJson(object);
            Map<String, Object> beanMap = JGPUtil.jsonToMap(json);
            Model model = (Model) object;
            Map<String, Object> modelExtData = model.getExtData();
            if (Objects.nonNull(modelExtData)) {
                beanMap.putAll(modelExtData);
            }
            return beanMap;
        } else {
            return object;
        }
    }
}
